#include<cstdio>
#include<iostream>
#include<stack>
#include<map>

namespace LexicalAnalysis{
    const int MAXSIZE = 512;
    char buf[MAXSIZE], *ptr = buf;
    struct WORD{
        std::string content;
        int type_num;
    }word;
    std::map<std::string, int>table;
    bool is_letter() {
        return *ptr >= 'a' && *ptr <= 'z';
    }


    bool is_digit() {
        return *ptr >= '0' && *ptr <= '9';
    }


    int find_token(std::string& token) {
        if (table.count(token)) {
            return table[token];
        }
        return 10;
    }


    void scan() {
        word.type_num = 10;
        word.content = "";
        while (*ptr == ' ' || *ptr == '\n' || *ptr == '\t') {
            ++ptr;
        }
        if (is_letter()) {
            while (is_letter() || is_digit()) {
                word.content += *ptr;
                ++ptr;
            }
            word.type_num = find_token(word.content);
            return;
        }
        if (is_digit()) {
            while (is_digit()) {
                word.content += *ptr;
                ++ptr;
            }
            word.type_num = 11;
            return;
        }
        switch (*ptr) {
            case '+' :
                word.type_num = 13;
                word.content += *ptr;
                ++ptr;
                break;
            case '-' :
                word.type_num = 14;
                word.content += *ptr;
                ++ptr;
                break;
            case '*' :
                word.type_num = 15;
                word.content += *ptr;
                ++ptr;
                break;
            case '/' :
                word.type_num = 16;
                word.content += *ptr;
                ++ptr;
                break;
            case ':' :
                word.type_num = 17;
                word.content += *ptr;
                ++ptr;
                if (*ptr == '=') {
                    word.content += *ptr;
                    word.type_num = 18;
                    ++ptr;
                }
                break;
            case '<' :
                word.type_num = 20;
                word.content += *ptr;
                ++ptr;
                if (*ptr == '>') {
                    word.content += *ptr;
                    word.type_num = 21;
                    ++ptr;
                } else if(*ptr == '=') {
                    word.content += *ptr;
                    word.type_num = 22;
                    ++ptr;
                }
                break;
            case '>' :
                word.type_num = 23;
                word.content += *ptr;
                ++ptr;
                if (*ptr == '=') {
                    word.content += *ptr;
                    word.type_num = 24;
                    ++ptr;
                }
                break;
            case '=' :
                word.type_num = 25;
                word.content += *ptr;
                ++ptr;
                break;
            case ';' :
                word.type_num = 26;
                word.content += *ptr;
                ++ptr;
                break;
            case '(' :
                word.type_num = 27;
                word.content += *ptr;
                ++ptr;
                break;
            case ')' :
                word.type_num = 28;
                word.content += *ptr;
                ++ptr;
                break;
            case EOF :
                word.type_num = 0;
                break;
            default:
                word.type_num = -1;
                word.content = "ERROR";
                ++ptr;
        }
    }


    void LexicalAnalysis() {
        table.insert({"begin", 1});
        table.insert({"if", 2});
        table.insert({"then", 3});
        table.insert({"while", 4});
        table.insert({"do", 5});
        table.insert({"end", 6});
        FILE* input = fopen("input.txt","r");
        FILE* output = fopen("LexicalAnalysisResult.txt","w");

        int _size = fread(buf, 1, MAXSIZE, input);
        buf[_size] = EOF;
        word.type_num = -1;
        while ((*ptr) != EOF) {
            scan();
            if (word.type_num != 0) {
                fprintf(output, "%c", word.type_num);
                //fprintf(output, "(%s, %d)\n", word.content.c_str(), word.type_num);
            }
        }
        fprintf(output, "%c", 0);
        fclose(input);
        fclose(output);
    }
}


const int acc = -1024;
const int MAXSIZE = 512;
char buf[MAXSIZE], *ptr = buf;

std::stack<int>Analysis_stack;
int BETA[16];
int LEFT[16];
int ACTION[64][64];
int GOTO[64][64];
void Initialize(){
    BETA[1] = 3;
    BETA[2] = 1;
    BETA[3] = 3;
    BETA[4] = 1;
    BETA[5] = 3;
    BETA[6] = 1;

    LEFT[1] = 40;
    LEFT[2] = 40;
    LEFT[3] = 41;
    LEFT[4] = 41;
    LEFT[5] = 42;
    LEFT[6] = 42;

    ACTION[0][10] = 5;
    ACTION[0][11] = 5;
    ACTION[0][27] = 4;

    ACTION[1][13] = 6;
    ACTION[1][0]  = acc;

    ACTION[2][13] = -2;
    ACTION[2][15] = 7;
    ACTION[2][28] = -2;
    ACTION[2][0] =  -2;

    ACTION[3][13] = -4;
    ACTION[3][15] = -4;
    ACTION[3][28] = -4;
    ACTION[3][0] =  -4;

    ACTION[4][10] = 5;
    ACTION[4][11] = 5;
    ACTION[4][27] = 4;

    ACTION[5][13] = -6;
    ACTION[5][15] = -6;
    ACTION[5][28] = -6;
    ACTION[5][0] = -6;

    ACTION[6][10] = 5;
    ACTION[6][11] = 5;
    ACTION[6][27] = 4;

    ACTION[7][10] = 5;
    ACTION[7][11] = 5;
    ACTION[7][27] = 4;

    ACTION[8][13] = 6;
    ACTION[8][28] = 11;

    ACTION[9][13] = -1;
    ACTION[9][15] = 7;
    ACTION[9][28] = -1;
    ACTION[9][0]  = -1;

    ACTION[10][13] = -3;
    ACTION[10][15] = -3;
    ACTION[10][28] = -3;
    ACTION[10][0]  = -3;

    ACTION[11][13] = -5;
    ACTION[11][15] =  -5;
    ACTION[11][28] = -5;
    ACTION[11][0]  = -5;

    GOTO[0][40] = 1;
    GOTO[0][41] = 2;
    GOTO[0][42] = 3;

    GOTO[4][40] = 8;
    GOTO[4][41] = 2;
    GOTO[4][42] = 3;

    GOTO[6][41] = 9;
    GOTO[6][42] = 3;

    GOTO[7][42] = 10;
}
int main() {
    LexicalAnalysis::LexicalAnalysis();
    Initialize();
    FILE* input  = fopen("LexicalAnalysisResult.txt","r");
    FILE* output = fopen("SyntaxAnalysisResult.txt","w");
    int _size = fread(buf, 1, MAXSIZE, input);
    buf[_size] = EOF;
    Analysis_stack.push(0);
    while (true) {
        int current_status = Analysis_stack.top();
        printf("!%d %d\n",current_status, *ptr);
        if (ACTION[current_status][*ptr] == acc) {
            fprintf(output, "success\n");
            break;
        } else if (ACTION[current_status][*ptr] > 0) {
            Analysis_stack.push(ACTION[current_status][*ptr]);
            ++ptr;
        } else if (ACTION[current_status][*ptr] < 0) {
            int rule = -ACTION[current_status][*ptr];
            for (int i = 0; i < BETA[rule]; ++i) {
                Analysis_stack.pop();
            }
            current_status = Analysis_stack.top();
            Analysis_stack.push(GOTO[current_status][LEFT[rule]]);
        } else {
            //printf("!%d %d\n",current_status, *ptr);
            fprintf(output, "error\n");
            break;
        }

    }
    return 0;
}
